﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

namespace Ymatou.ServiceCenter.Common
{
    public static class DictionaryExtensions
    {
        public static IDictionary<TKey, TValue> Sort<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");

            return new SortedDictionary<TKey, TValue>(dictionary);
        }

        public static IDictionary<TKey, TValue> Sort<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            if (comparer == null)
                throw new ArgumentNullException("comparer");

            return new SortedDictionary<TKey, TValue>(dictionary, comparer);
        }

        public static IDictionary<TKey, TValue> SortByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
        {
            return (new SortedDictionary<TKey, TValue>(dictionary)).OrderBy(kvp => kvp.Value).ToDictionary(item => item.Key, item => item.Value);
        }

        public static IDictionary<TValue, TKey> Invert<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            return dictionary.ToDictionary(pair => pair.Value, pair => pair.Key);
        }

        public static void AddListItem<TKey, TItem>(this IDictionary<TKey, IList<TItem>> dic, TKey key, TItem item)
        {
            if (dic == null)
                return;
            IList<TItem> list = dic.ContainsKey(key) ? dic[key] : null;
            list = list ?? new List<TItem>();
            list.Add(item);
            dic[key] = list;
        }

        public static void AddUnqiueListItem<TKey, TItem>(this IDictionary<TKey, IList<TItem>> dic, TKey key, TItem item)
        {
            if (dic == null)
                return;
            IList<TItem> list = dic.ContainsKey(key) ? dic[key] : null;
            list = list ?? new List<TItem>();
            if (!list.Contains(item))
                list.Add(item);
            dic[key] = list;
        }

        public static void RemoveListItem<TKey, TItem>(this IDictionary<TKey, IList<TItem>> dic, TKey key, TItem item)
        {
            if (dic == null || !dic.ContainsKey(key))
                return;
            dic[key].Remove(item);
        }

        public static void AddDictionaryItem<TKey, TItemKey, TItemValue>(this IDictionary<TKey, IDictionary<TItemKey, TItemValue>> dic, TKey key, TItemKey itemKey, TItemValue itemValue)
        {
            if (dic == null)
                return;
            IDictionary<TItemKey, TItemValue> itemDic = dic.ContainsKey(key) ? dic[key] : null;
            itemDic = itemDic ?? new Dictionary<TItemKey, TItemValue>();
            itemDic[itemKey] = itemValue;
            dic[key] = itemDic;
        }

        public static void RemoveDictionaryItem<TKey, TItemKey, TItemValue>(this IDictionary<TKey, IDictionary<TItemKey, TItemValue>> dic, TKey key, TItemKey itemKey)
        {
            if (dic == null || !dic.ContainsKey(key))
                return;
            dic[key].Remove(itemKey);
        }

        public static Hashtable ToHashTable<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
        {
            var table = new Hashtable();
            foreach (var item in dictionary)
                table.Add(item.Key, item.Value);

            return table;
        }

        public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return dictionary.ContainsKey(key) ? dictionary[key] : default(TValue);
        }


        public static bool EquivalentTo<K, V>(this IDictionary<K, V> thisMap, IDictionary<K, V> otherMap)
        {
            if (thisMap == null || otherMap == null) return thisMap == otherMap;
            if (thisMap.Count != otherMap.Count) return false;

            foreach (var entry in thisMap)
            {
                V otherValue;
                if (!otherMap.TryGetValue(entry.Key, out otherValue)) return false;
                if (!Equals(entry.Value, otherValue)) return false;
            }

            return true;
        }


        public static object Get(this IDictionary dic, object key)
        {
            if (dic != null && dic.Contains(key))
            {
                return dic[key];
            }
            return null;
        }



        public static void Set(this IDictionary dic, object key, object value)
        {
            dic[key] = value;
        }

        public static NameValueCollection ToNameValueCollection<TKey, TValue>(this IDictionary<TKey, TValue> dic)
        {
            NameValueCollection nameValues = new NameValueCollection();
            foreach (var key in dic.Keys)
            {
                nameValues[key.ToString()] = dic[key] == null ? "" : dic[key].ToString();
            }
            return nameValues;
        }

        public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> source, IDictionary<TKey, TValue> dic)
        {
            if (dic == null) return source;
            foreach (var item in dic)
            {
                if (!source.ContainsKey(item.Key))
                {
                    source.Add(item);
                }
            }
            return source;
        }
    }
}

